from sqlalchemy.orm.attributes import flag_modified
from sqlalchemy_utils.models import generic_repr

from redash.settings.organization import settings as org_settings

from .base import db, Column, primary_key
from .mixins import TimestampMixin
from .types import MutableDict, PseudoJSON
from .users import User, Group
from .dazdata import Enums,TimeStruct,TimeSerial,QueryTimeSerial,QueryShowField
from .contract import (
    CustomerTemp,
    ContractApply,
    EmployeeTemp,
    Contracts,
    ContractSeal,
    ContractRecord,
    ContractChange,
    ContractProgress,
    ContractSettle,
    ContractStop,
    ContractFinish,
    Attaches,
    Templates,
    GlobalSetting,
    ContractSuspend,
)
from .workflow import Workflow,Workflow_bill_state,Workflow_transition,Workflow_state,Tabletype,Workflow_action

@generic_repr("id", "name", "slug")
class Organization(TimestampMixin, db.Model):
    SETTING_GOOGLE_APPS_DOMAINS = "google_apps_domains"
    SETTING_IS_PUBLIC = "is_public"

    id = primary_key("Organization")
    name = Column(db.String(255))
    slug = Column(db.String(255), unique=True)
    settings = Column(MutableDict.as_mutable(PseudoJSON))
    groups = db.relationship("Group", lazy="dynamic")
    enums = db.relationship("Enums", lazy="dynamic")
    timestruct = db.relationship("TimeStruct", lazy="dynamic")
    timeserial = db.relationship("TimeSerial", lazy="dynamic")
    query_timeserial = db.relationship("QueryTimeSerial", lazy="dynamic")
    customertemp = db.relationship("CustomerTemp", lazy="dynamic")
    contractapply = db.relationship("ContractApply", lazy="dynamic")
    employeetemp = db.relationship("EmployeeTemp", lazy="dynamic")
    contracts = db.relationship("Contracts", lazy="dynamic")
    contractseal = db.relationship("ContractSeal", lazy="dynamic")
    contractsuspend = db.relationship("ContractSuspend", lazy="dynamic")
    contractrecord = db.relationship("ContractRecord", lazy="dynamic")
    contractchange = db.relationship("ContractChange", lazy="dynamic")
    contractprogress = db.relationship("ContractProgress", lazy="dynamic")
    contractsettle = db.relationship("ContractSettle", lazy="dynamic")
    contractstop = db.relationship("ContractStop", lazy="dynamic")
    contractfinish = db.relationship("ContractFinish", lazy="dynamic")
    attaches = db.relationship("Attaches", lazy="dynamic")
    templates = db.relationship("Templates", lazy="dynamic")
    globalsetting = db.relationship("GlobalSetting", lazy="dynamic")
    workflow = db.relationship("Workflow", lazy="dynamic")
    workflow_bill_state = db.relationship("Workflow_bill_state", lazy="dynamic")
    workflow_transition = db.relationship("Workflow_transition", lazy="dynamic")
    workflow_state = db.relationship("Workflow_state", lazy="dynamic")
    tabletype = db.relationship("Tabletype", lazy="dynamic")
    workflow_action = db.relationship("Workflow_action", lazy="dynamic")
    queryshowfield = db.relationship("QueryShowField", lazy="dynamic")
    events = db.relationship("Event", lazy="dynamic", order_by="desc(Event.created_at)")

    __tablename__ = "organizations"

    def __str__(self):
        return "%s (%s)" % (self.name, self.id)

    @classmethod
    def get_by_slug(cls, slug):
        return cls.query.filter(cls.slug == slug).first()

    @classmethod
    def get_by_id(cls, _id):
        return cls.query.filter(cls.id == _id).one()

    @property
    def default_group(self):
        return self.groups.filter(
            Group.name == "default", Group.type == Group.BUILTIN_GROUP
        ).first()

    @property
    def google_apps_domains(self):
        return self.settings.get(self.SETTING_GOOGLE_APPS_DOMAINS, [])

    @property
    def is_public(self):
        return self.settings.get(self.SETTING_IS_PUBLIC, False)

    @property
    def is_disabled(self):
        return self.settings.get("is_disabled", False)

    def disable(self):
        self.settings["is_disabled"] = True

    def enable(self):
        self.settings["is_disabled"] = False

    def set_setting(self, key, value):
        if key not in org_settings:
            raise KeyError(key)

        self.settings.setdefault("settings", {})
        self.settings["settings"][key] = value
        flag_modified(self, "settings")

    def get_setting(self, key, raise_on_missing=True):
        if key in self.settings.get("settings", {}):
            return self.settings["settings"][key]

        if key in org_settings:
            return org_settings[key]

        if raise_on_missing:
            raise KeyError(key)

        return None

    @property
    def admin_group(self):
        return self.groups.filter(
            Group.name == "admin", Group.type == Group.BUILTIN_GROUP
        ).first()

    def has_user(self, email):
        return self.users.filter(User.email == email).count() == 1
